package com.onefish.toolkit.natives.support;

import com.sun.jna.Library;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 三方本地方法动态库抽象泛型加载器
 *
 * @author onefish
 */
public abstract class AbstractNativeLibraryLoader<T> {
    private static final ConcurrentHashMap<String, String> ARCH = new ConcurrentHashMap<>();

    //  区分不同架构
    static {
        ARCH.put("x86_64", "x64");
        ARCH.put("x86", "x86");
        ARCH.put("amd64", "x64");
        ARCH.put("arm64", "aarch64");
        ARCH.put("aarch64", "aarch64");
        ARCH.put("mips64el", "mips64el");
        ARCH.put("sw_64", "sw64");
        ARCH.put("sw64", "sw64");
        ARCH.put("loongarch64", "loongarch64");
    }

    private String libPath;
    private CustomNativeEnum customType;

    public AbstractNativeLibraryLoader() {}

    /**
     * 获取 cpu架构
     *
     * @return 架构
     */
    public static String obtainCpuArch() {
        return ARCH.getOrDefault(System.getProperty("os.arch"), "unknown");
    }

    /**
     * 判断平台类型（不考虑 mac）
     *
     * @return true or false
     */
    public static boolean judgeIsLinux() {
        return System.getProperty("os.name").toLowerCase().contains("linux");
    }

    /**
     * 通用模板方法
     */
    public void generateTemplateStruct() {
        //  定义三方枚举类型
        this.customType = setTripartite();
        //  生成三方本地方法库路径
        this.libPath = generateLibPath(this.customType);
        //  自定义业务逻辑
        customBizLogic();

    }

    /**
     * 加载三方本地方法库
     *
     * @param libPath        库路径
     * @param interfaceClass 库接口类型
     * @return T 库接口实例
     */
    public <T extends Library> T load(String libPath, Class<T> interfaceClass) {
        return LibraryPool.load(libPath, interfaceClass);
    }

    protected abstract CustomNativeEnum setTripartite();

    protected void customBizLogic() {
    }

    private String generateLibPath(CustomNativeEnum customNativeEnum) {
        if (customNativeEnum == null) throw new NullPointerException("customNativeEnum is null");
        String arch = obtainCpuArch();
        String archFolder = generateArchFolder(arch);
        String archFile = generateArchFile(customNativeEnum.getCustomLibName(), arch);
        String customFolder = customNativeEnum.getCustomFolder();
        //  形式如：one-fish/linux-x64/libbiz.so
        return String.format("%s%s%s%s%s", customFolder, "/", archFolder, "/", archFile);
    }

    private String generateArchFolder(String arch) {
        return judgeIsLinux() ? "linux-" + arch : "windows-" + arch;
    }

    private String generateArchFile(String libPrefName, String arch) {
        return judgeIsLinux() ? "lib" + libPrefName + "_" + arch + ".so" : libPrefName + "_" + arch + ".dll";
    }

    public String getLibPath() {
        return libPath;
    }

    public void setLibPath(String libPath) {
        this.libPath = libPath;
    }

    public CustomNativeEnum getCustomType() {
        return customType;
    }

    public void setCustomType(CustomNativeEnum customType) {
        this.customType = customType;
    }

}
